package com.golxen.framework.netty.session.base;


import com.golxen.framework.PBPacket.PBPacket;
import com.golxen.utils.LogUtil;
import org.slf4j.Logger;

import java.util.ArrayList;
import java.util.List;

public abstract class AbstractSessionGroup<T extends AbstractSession> extends AbstractSession {

	private static Logger logger = LogUtil.COMMON;

	protected AbstractSession[] sessions;

	private int indexNum = 0;

	public AbstractSessionGroup(int size) {
		init(size);
	}

	protected synchronized boolean init(int size) {
		close();
		sessions = new AbstractSession[size];
		return true;
	}

	protected abstract T connect(int index) throws Exception;

	private static boolean isAlvin(AbstractSession session) {
		return session != null && session.isAlive();
	}

	@Override
	public void write(PBPacket msg) {
		int size = sessions != null ? sessions.length : 0;
		int random = (int) (Math.random() * size);
		//根据玩家编号取模，保证消息有序,因为有多个channel
		if (msg.getPlayerId() > 0) {
			random = (int) (msg.getPlayerId() % sessions.length);
		} else {
		    logger.info("write msg code {} with random session idx = {} size = {}", msg.getCode(), random, size);
		}
		AbstractSession session = sessions[random];
		if (!isAlvin(session)) {
			int i = 0;
			for (AbstractSession tempSession : sessions) {
				if (isAlive(tempSession)) {
					session = tempSession;
					break;
				}
				i++;
			}

			if (!isAlive(session)) {
				logger.error("all session is disconnect");
				return;
			}

			logger.error("session connect fail : index = " + random + " msg = " + msg + "，rediscover link , index : " + i);
		}
		
		session.write(msg);
	}

	public void sessionSendMsg(PBPacket msg) {
		AbstractSession session = sessions[indexNum % sessions.length];
		msg.setPlayerId(indexNum % sessions.length);
		if (!isAlive(session)) {
			int i = 0;
			for (AbstractSession tempSession : sessions) {
				if (isAlive(tempSession)) {
					msg.setPlayerId(i);
					session = tempSession;
					break;
				}
				i++;
			}

			if (!isAlive(session)) {
				logger.error("all session is disconnect");
				return;
			}

			logger.error("session connect fail : index = " + indexNum % sessions.length + " msg = " + msg + "，rediscover link , index : " + i);
		}
		indexNum++;
		session.write(msg);
	}


	public void write(long userId, PBPacket msg) {
		msg.setPlayerId(userId);
		write(msg);
	}

	@Override
	public void flush() {

	}

	@Override
	public void close() {
		int size = sessions != null ? sessions.length : 0;
		for (int i = 0; i < size; i++) {
			AbstractSession session = sessions[i];
			if (session != null) {
				session.close();
			}
		}
		sessions = null;
	}

	public T get(int index) {
		int size = (sessions != null) ? sessions.length : 0;
		if (index < 0 || index >= size) {
			return null;
		}
		@SuppressWarnings("unchecked")
		T session = (T) sessions[index];
		if (!isAlvin(session)) {
			return null;
		}
		return session;
	}

	public void keep() {

	}

	protected static boolean isAlive(AbstractSession session) {
		return session != null && session.isAlive();
	}

	public List<T> getAll() {
		List<T> list = new ArrayList<>();
		int size = (sessions != null) ? sessions.length : 0;
		for (int i = 0; i < size; i++) {
			@SuppressWarnings("unchecked")
			T session = (T) sessions[i];
			list.add(session);
		}
		return list;
	}

	protected void writeToAll(PBPacket msg) {
		int size = (sessions != null) ? sessions.length : 0;
		for (int i = 0; i < size; i++) {
			@SuppressWarnings("unchecked")
			T session = (T) sessions[i];
			if (isAlive(session)) {
				session.write(msg);
			}
		}
	}

	public void addSession(AbstractSession socketSession, int index) {

	}

	public AbstractSession[] getSessions() {
		return sessions;
	}

}
